home *** CD-ROM | disk | FTP | other *** search
Text File | 1992-07-15 | 8.6 KB | 313 lines | [TEXT/MPS ] |
- PROGRAM ledApp;
-
- {
- This faceless background task counts to 7 on an extended keyboard's lights.
- The application quits when the user holds down the shift and caps lock
- keys, or when it receives a quit Apple Event.
-
- ledApp installs a Time Manager task which wakes the application every
- 500 ms.
-
- June 1991 by Greg Robbins
- }
-
-
- USES
-
- Memtypes, AppleEvents, OSIntf, PackIntf, { Standard Includes }
- GestaltEqu, Timer;
-
- CONST
-
- kSleepVal = MAXLONGINT; { for WaitNextEvent }
- kTimerPrimer = 500; { for PrimeTime, 500 ms }
-
- { keyboard ADB constants }
- kTalkCommand = 8+4;
- kListenCommand = 8;
- kLEDRegister = 2;
-
- kShiftKeyBit = 56;
- kShiftLockBit = 57;
-
- TYPE
-
- ADBregBuffType = PACKED ARRAY[0..8] of BYTE; { data buffer for ADB }
-
- { enhance the time manager record with my A5 so the
- task can access global variables }
- enhTMTaskRec = RECORD
- theTMTask: TMTask;
- myA5: LONGINT
- END;
- enhTMTaskPtr = ^enhTMTaskRec;
-
- VAR
-
- myEvtRec: EventRecord;
- timeMgrVers, aePresent: LONGINT; { Gestalt values }
- quitFlag, nullEvtFlag: BOOLEAN;
- ledPattern: BYTE;
-
- myTMTaskRec: enhTMTaskRec;
- timeTaskFlag: BOOLEAN;
-
- myNMRec: NMRec; { notification manager record }
- notificationCompleteFlag: BOOLEAN;
-
- anOSErr: OSErr;
- myPSN: ProcessSerialNumber;
-
- myKeyMap: KeyMap;
-
-
- FUNCTION getTMInfo: enhTMTaskPtr;
- INLINE $2E89; { put A1 on stack }
-
- PROCEDURE myTimeTask;
- { this routine is executed when the primed time manager task comes due }
- VAR
- recPtr: enhTMTaskPtr;
- oldA5: LONGINT;
- anOSErr: LONGINT;
-
- BEGIN
- recPtr := getTMInfo; { get pointer to record for this task }
-
- oldA5 := SetA5(recPtr^.myA5); { we want globals }
-
- { flag that time is up and wake the app }
- timeTaskFlag := TRUE;
- anOSErr := WakeUpProcess(myPSN);
-
- { make this task periodic }
- PrimeTime(QElemPtr(recPtr), kTimerPrimer);
-
- { now back to our previously scheduled A5 world }
- oldA5 := SetA5(oldA5);
- END;
-
- PROCEDURE myNMResponseProc(myNMRecPtr: NMRecPtr);
- { flag that notification has been executed }
- VAR
- oldA5: LONGINT;
- BEGIN
- oldA5 := SetA5(myNMRecPtr^.nmRefCon);
- notificationCompleteFlag := TRUE;
- oldA5 := SetA5(oldA5);
- { would have been simpler just to pass the flag address rather than A5 }
- END;
-
-
- PROCEDURE DoNotification(nmString: Str255);
- { put up notification alert }
- BEGIN
- { set up notification manager record for alert notification }
- myNMRec.qType := ORD(nmType);
- myNMRec.nmMark := 0;
- myNMRec.nmIcon := NIL;
- myNMRec.nmSound := Handle(-1);
- myNMRec.nmStr := @nmString;
- myNMRec.nmResp := @myNMResponseProc;
- myNMRec.nmRefCon := SetCurrentA5;
-
- notificationCompleteFlag := FALSE;
-
- anOSErr := NMInstall(@myNMRec);
-
- REPEAT
- nullEvtFlag := EventAvail(everyEvent, myEvtRec); { to allow notification }
- UNTIL (anOSErr <> 0) OR (notificationCompleteFlag);
-
- anOSErr := NMRemove(@myNMRec);
- END;
-
- PROCEDURE DropDead(sTemp: Str255);
- { unresolvable failure }
-
- BEGIN
- quitFlag := TRUE;
- DoNotification(sTemp);
- END;
-
- FUNCTION GetA2: LONGINT;
- INLINE $2E8A; { put A2 on stack }
-
- PROCEDURE CompADBOp;
- { completion routine for ADB talks and listens }
- TYPE
- boolPtr = ^BOOLEAN;
- VAR
- completionFlagPtr: boolPtr;
- BEGIN
- { set flag to indicate completion routine has run; A2 points to the flag }
- completionFlagPtr := boolPtr(GetA2);
- completionFlagPtr^ := TRUE;
- END;
-
- PROCEDURE DoSetLEDs(ledPat: BYTE);
- { set the leds to the given pattern }
- TYPE
- ADBregBuffType = PACKED ARRAY[0..8] of BYTE;
-
- VAR
- retCode: OSErr;
- i: INTEGER; { index through ADB devices }
- numADBs: INTEGER; { total number of ADB devices }
- anADBDB: array[1..16] of ADBDataBlock; { data block for each device }
- anADBadd: array[1..16] of ADBAddress; { address of each device }
- regBuff: ADBregBuffType; { buffer for ADBOp commands }
- oldReg: BYTE;
- completionFlag: BOOLEAN;
-
- BEGIN
- numADBs := CountADBs;
-
- FOR i:=1 to numADBs DO
- BEGIN
- { get an address for an ADB device }
- anADBadd[i] := GetIndADB(anADBDB[i], i);
-
- { a keyboard has an original address of 2, but the actual ADB address
- may change if there is a conflict; a U.S. extended keyboard has a
- device type ("handler ID") of 2, but unfortunately some other ADB devices
- also do }
- IF (anADBDB[i].origADBAddr = 2) AND (anADBDB[i].devType = 2) THEN { ext keyboard }
- BEGIN
- regBuff[0] := BYTE(2); { initial data buffer length }
-
- { talk }
- completionFlag := FALSE;
- retCode := ADBOp(@completionFlag, @CompADBOp, @regBuff,
- kTalkCommand + kLEDRegister + 16 * anADBadd[i]);
-
- IF retCode <> noErr THEN
- EXIT(DoSetLEDs);
-
- { do nothing until completion routine has run }
- REPEAT
- ;
- UNTIL completionFlag;
-
- { extended keyboard has a word of data, LEDs are low 3 bits }
- oldReg := regBuff[2];
-
- { set the specified bits; note that a clear bit indicates an lit LED }
- regBuff[2] := BOR(BAND(oldReg, 255-7), 7 - LedPat);
-
- { listen }
- completionFlag := FALSE;
- retCode := ADBOp(@completionFlag, @CompADBOp, @regBuff,
- kListenCommand + kLEDRegister + 16 * anADBadd[i]);
-
- { do nothing until completion routine has run }
- REPEAT
- ;
- UNTIL (retCode <> noErr) OR (completionFlag);
-
- END; { if }
- END; { for }
- END; { DoSetLEDs }
-
- PROCEDURE DoHighLevel(anAERec: EventRecord);
- { handle high-level events }
- BEGIN
- IF AEProcessAppleEvent(anAERec) <> noErr THEN
- DropDead('ledApp cannot run: cannot process Apple Events');
- END;
-
- FUNCTION DoAEOpen(theAEvent: AppleEvent; reply: AppleEvent; refcon: LONGINT): OSErr;
- BEGIN
- DoAEOpen := noErr;
- END; { Do AEOpen }
-
- FUNCTION DoAEOpenDoc(theAEvent: AppleEvent; reply: AppleEvent; refcon: LONGINT): OSErr;
- BEGIN
- DoAEOpenDoc := errAEEventNotHandled;
- END; { DoAEOpenDoc }
-
- FUNCTION DoAEPrintDoc(theAEvent: AppleEvent; reply: AppleEvent; refcon: LONGINT): OSErr;
- BEGIN
- DoAEPrintDoc := errAEEventNotHandled;
- END; { DoAEPrintDoc }
-
- FUNCTION DoAEQuit(theAEvent: AppleEvent; reply: AppleEvent; refcon: LONGINT): OSErr;
- BEGIN
- quitFlag := TRUE;
- DoAEQuit := noErr;
- END; { DoAEQuit }
-
- PROCEDURE InitStuff;
- { Apple Events handler installation and other initialization}
- BEGIN
- IF Gestalt(gestaltAppleEventsAttr, aePresent) = noErr THEN
- BEGIN
- IF AEInstallEventHandler(kCoreEventClass, kAEOpenApplication, @DoAEOpen, 0, FALSE) <> noErr THEN
- DropDead('ledApp cannot run: cannot install open application event');
- IF AEInstallEventHandler(kCoreEventClass, kAEOpenDocuments, @DoAEOpenDoc, 0, FALSE) <> noErr THEN
- DropDead('ledApp cannot run: cannot install open document event');
- IF AEInstallEventHandler(kCoreEventClass, kAEPrintDocuments, @DoAEPrintDoc, 0, FALSE) <> noErr THEN
- DropDead('ledApp cannot run: cannot install print document event');
- IF AEInstallEventHandler(kCoreEventClass, kAEQuitApplication, @DoAEQuit, 0, FALSE) <> noErr THEN
- DropDead('ledApp cannot run: cannot install quit event');
- END
- ELSE DropDead('ledApp cannot run: Apple Events not present');
-
- IF Gestalt(gestaltTimeMgrVersion, timeMgrVers) <> noErr THEN
- DropDead('ledApp cannot run: time manager problem');
- IF timeMgrVers = 1 THEN { can't use standard time manager for re-priming }
- DropDead('ledApp cannot run: wrong time manager version');
-
- END; { InitStuff }
-
- BEGIN {main}
-
- quitFlag := FALSE;
- timeTaskFlag := FALSE;
-
- InitStuff;
- anOSErr := GetCurrentProcess(myPSN);
-
- { turn LEDs off }
- DoSetLEDs(0);
-
- { set up task record for time manager }
- myTMTaskRec.theTMTask.tmAddr := @myTimeTask;
- myTMTaskRec.theTMTask.tmCount := 0;
- myTMTaskRec.myA5 := SetCurrentA5;
-
- InsTime(@myTMTaskRec);
-
- { activate time manager }
- PrimeTime(@myTMTaskRec, kTimerPrimer);
-
- { main event loop; quitFlag may be set already }
- WHILE NOT(quitFlag) DO
- BEGIN
- IF timeTaskFlag THEN
- { time manager task has run }
- BEGIN
- ledPattern := (ledPattern + 1) MOD 8;
- DoSetLEDs(ledPattern);
- timeTaskFlag := FALSE;
- END;
-
- { sleep until awoken by the time manager task or by an Apple Event }
- nullEvtFlag := WaitNextEvent(highLevelEventMask, myEvtRec, kSleepVal, NIL);
-
- IF myEvtRec.what = kHighLevelEvent THEN
- DoHighLevel(myEvtRec);
-
- { quit if shift and caps lock are down }
- GetKeys(myKeyMap);
- IF myKeyMap[kShiftKeyBit] AND myKeyMap[kShiftLockBit] THEN
- quitFlag := TRUE;
- END;
-
- { make sure time manager task isn't executed after app is gone }
- RmvTime(@myTMTaskRec);
-
- DoSetLEDs(0); { turn off leds }
-
- END.
-